package org.mysfit.ctp4j.core.service.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.mysfit.ctp4j.api.vo.BonsVO;
import org.mysfit.ctp4j.api.vo.QuoteVO;
import org.mysfit.ctp4j.core.MyCThostFtdcTraderHelperSpi;
import org.mysfit.ctp4j.core.service.CommonService;
import org.mysfit.ctp4j.core.service.PolyService;
import org.mysfit.ctp4j.infra.entity.SkData;
import org.mysfit.ctp4j.infra.enums.TFtdcHedgeFlagType;
import org.mysfit.ctp4j.infra.enums.TFtdcOffsetFlagType;
import org.mysfit.ctp4j.infra.pojo.CtpConfig;
import org.mysfit.ctp4j.infra.pojo.CtpUser;
import org.mysfit.ctp4j.infra.utils.CtpTypeConstans;
import org.mysfit.ctp4j.infra.utils.TradeConvertUtils;
import org.mysfit.ctp4j.infra.utils.TradeTimeUtils;
import org.mysfit.ctp4j.infra.utils.TradeUtils;

import ctp.thosttraderapi.CThostFtdcInputOrderField;
import ctp.thosttraderapi.CThostFtdcInputQuoteField;
import ctp.thosttraderapi.CThostFtdcQuoteField;
import ctp.thosttraderapi.CThostFtdcTradeField;
import ctp.thosttraderapi.CThostFtdcTraderApi;
import ctp.thosttraderapi.THOST_TE_RESUME_TYPE;

/**
 * 
 * @author long.gf
 * @since 2022-12-06
 *
 */
public class TradeHelper {

	private PolyService polyService;

	private CommonService commonService;
	
	private CThostFtdcTraderApi traderApi;
	
	private CtpUser ctpUser;
	
	public static Map<String, TradeHelper> helperMap = new HashMap<String, TradeHelper>();
	
	public static TradeHelper getInstance(String userId, PolyService polyService, CommonService commonService) {
		TradeHelper helper = helperMap.get(userId);
		if(null == helper) {
			helper = new TradeHelper(polyService,commonService);
			helperMap.put(userId, helper);
		}
		return helper;
	}
	
	private TradeHelper(PolyService polyService, CommonService commonService) {
		this.polyService = polyService;
		this.commonService = commonService;
	}
		
	
	
	public void initTradeApi(String userId) {
		if(null == traderApi) {
			CtpConfig ctpConfig = commonService.getConfig();
			ctpUser = commonService.getUser(userId);
			traderApi = CThostFtdcTraderApi.CreateFtdcTraderApi();
			MyCThostFtdcTraderHelperSpi traderSpi = new MyCThostFtdcTraderHelperSpi(ctpUser, traderApi, this);
			traderApi.RegisterSpi(traderSpi);
			traderApi.RegisterFront(ctpConfig.getTradeFront());
			traderApi.SubscribePublicTopic(THOST_TE_RESUME_TYPE.THOST_TERT_QUICK);
			traderApi.SubscribePrivateTopic(THOST_TE_RESUME_TYPE.THOST_TERT_QUICK);
			traderApi.Init();
			traderApi.Join();
		}
	}
	
	public void doCtpQuote(QuoteVO q) {
		CThostFtdcInputQuoteField pInputQuote = new CThostFtdcInputQuoteField();
		pInputQuote.setBrokerID(this.ctpUser.getBrokerId());
		pInputQuote.setInvestorID(this.ctpUser.getInvestorId());
		pInputQuote.setInstrumentID(q.getFid());
		pInputQuote.setAskVolume(TradeUtils.isDF(q.getDirection()) ? 0 :  q.getQty() );
		pInputQuote.setBidVolume(TradeUtils.isDF(q.getDirection()) ? q.getQty() :  0 );
		pInputQuote.setAskOffsetFlag(TFtdcOffsetFlagType.getTFtdcOffsetFlag(q.getKpFlag()));
		pInputQuote.setBidOffsetFlag(TFtdcOffsetFlagType.getTFtdcOffsetFlag(q.getKpFlag()));
		pInputQuote.setAskHedgeFlag(TFtdcHedgeFlagType.THOST_FTDC_HF_Speculation.getValue());
		pInputQuote.setBidHedgeFlag(TFtdcHedgeFlagType.THOST_FTDC_HF_Speculation.getValue());
		pInputQuote.setAskPrice(TradeUtils.isDF(q.getDirection()) ? 0 :  q.getCost() );
		pInputQuote.setBidPrice(TradeUtils.isDF(q.getDirection()) ? q.getCost() :  0 );
		int reqId = TradeTimeUtils.getCurrReqId();
		pInputQuote.setRequestID(reqId);
		pInputQuote.setForQuoteSysID(String.valueOf(reqId));
		pInputQuote.setAskOrderRef(String.valueOf(0));
		pInputQuote.setBidOrderRef(String.valueOf(reqId));
		q.setRequestId(reqId);
		traderApi.ReqQuoteInsert(pInputQuote, reqId);
	}
	
	 
	public void doTestCtpOrder(QuoteVO q) {
		CThostFtdcInputOrderField  order = new CThostFtdcInputOrderField();
		order.setBrokerID(this.ctpUser.getBrokerId());
		order.setInvestorID(this.ctpUser.getInvestorId());
		order.setExchangeID("SHFE");
		order.setInstrumentID("au2302");
		order.setOrderPriceType(CtpTypeConstans.THOST_FTDC_OPT_LimitPrice);
		order.setDirection(CtpTypeConstans.THOST_FTDC_D_Sell);
		order.setLimitPrice(404);
		order.setVolumeTotalOriginal(1);
		order.setContingentCondition(CtpTypeConstans.THOST_FTDC_CC_Immediately);
		order.setCombOffsetFlag(String.valueOf(CtpTypeConstans.THOST_FTDC_OF_Open));
		order.setCombHedgeFlag(String.valueOf(CtpTypeConstans.THOST_FTDC_HF_Speculation));
		order.setTimeCondition(CtpTypeConstans.THOST_FTDC_TC_GFD);
		order.setVolumeCondition(CtpTypeConstans.THOST_FTDC_VC_AV);
		order.setForceCloseReason(CtpTypeConstans.THOST_FTDC_FCC_NotForceClose);
		int reqId = TradeTimeUtils.getCurrReqId();
		order.setRequestID(reqId);
		traderApi.ReqOrderInsert(order, reqId);
	}
	
	public void doCtpOrder(QuoteVO q) {
		CThostFtdcInputOrderField  order = new CThostFtdcInputOrderField();
		order.setBrokerID(this.ctpUser.getBrokerId());
		order.setInvestorID(this.ctpUser.getInvestorId());
		order.setExchangeID("DCE");
		order.setInstrumentID(q.getFid());
		order.setDirection(TradeUtils.isDF(q.getDirection()) ? CtpTypeConstans.THOST_FTDC_D_Buy :  CtpTypeConstans.THOST_FTDC_D_Sell);
		order.setCombOffsetFlag(String.valueOf(TradeUtils.isKC(q.getKpFlag()) ? CtpTypeConstans.THOST_FTDC_OF_Open : CtpTypeConstans.THOST_FTDC_OF_Close));
		order.setCombHedgeFlag(String.valueOf(CtpTypeConstans.THOST_FTDC_HF_Speculation));
		order.setTimeCondition(CtpTypeConstans.THOST_FTDC_TC_IOC);
		order.setVolumeCondition(CtpTypeConstans.THOST_FTDC_VC_AV);
		order.setOrderPriceType(CtpTypeConstans.THOST_FTDC_OPT_BestPrice);
		order.setContingentCondition(CtpTypeConstans.THOST_FTDC_CC_Immediately);
		order.setForceCloseReason(CtpTypeConstans.THOST_FTDC_FCC_NotForceClose);
		order.setLimitPrice(q.getCost());
		order.setStopPrice(q.getCost() - 5);
		order.setVolumeTotalOriginal(q.getQty());
		order.setIsAutoSuspend(0);
		int reqId = TradeTimeUtils.getCurrReqId();
		order.setRequestID(reqId);
		q.setRequestId(reqId);
		traderApi.ReqOrderInsert(order, reqId);
	}
	
	
	private QuoteVO initQuoteVO(SkData sk,boolean isD,boolean isK) {
		QuoteVO q = new QuoteVO();
		q.setFid(sk.getFid());
		q.setFtime(sk.getFtime());
		q.setKpFlag(isK ? TradeUtils.K_FLAG : TradeUtils.P_FLAG);
		q.setDirection(isD ? TradeUtils.D_FX : TradeUtils.K_FX);
		q.setQty(1);
		q.setCost(isD ? sk.getFp().add(new BigDecimal(3)).doubleValue() : sk.getFp().subtract(new BigDecimal(3)).doubleValue());
		return q;
	}
	
	/**
	 *  接收行情信息
	 * @param sk
	 * @return
	 */
	public void doQuote(SkData sk) {
		QuoteVO q = TradeUtils.checkQuoteId(sk.getFid());
		if(null != q) {
			// cpt撤单接口
			TradeUtils.addCancleReq(q);
		}else {
			BonsVO b = polyService.checkPolyPC(sk);
			if(null != b) {
				q = initQuoteVO(sk,b.getDirection() > 0,false);
				q.setRefQuoteId(b.getQuoteId());
				//ctp 平仓接口
				this.doCtpQuote(q);
 				TradeUtils.addCancleReq(q);
			}
			String polyKcRes = polyService.checkPolyKC(sk);
 			if(StringUtils.isNotBlank(polyKcRes)) {
 				String polyNo = polyKcRes.split("_")[0];
 				String dkFlag = polyKcRes.split("_")[1];
 				q = initQuoteVO(sk,Integer.parseInt(dkFlag) > 0,true);
 				q.setPloyNo(polyNo);
 				this.doCtpQuote(q);
 				//ctp 开仓接口
 				TradeUtils.addQuoteReq(q);
 			}
		}
	}
	
	
	/**
	 *  接收行情信息
	 * @param sk
	 * @return
	 */
	public void doTestQuote(SkData sk) {
		QuoteVO q = TradeUtils.checkQuoteId(sk.getFid());
		if(null != q) {
			// cpt撤单接口
			TradeUtils.addCancleReq(q);
		}else {
			BonsVO b = polyService.checkPolyPC(sk);
			if(null != b) {
				q = initQuoteVO(sk,b.getDirection() > 0,false);
				q.setRefQuoteId(b.getQuoteId());
				//ctp 平仓接口
				
 				TradeUtils.addCancleReq(q);
			}
			String polyKcRes = polyService.checkPolyKC(sk);
 			if(StringUtils.isNotBlank(polyKcRes)) {
 				String polyNo = polyKcRes.split("_")[0];
 				String dkFlag = polyKcRes.split("_")[1];
 				q = initQuoteVO(sk,Integer.parseInt(dkFlag) > 0,true);
 				q.setPloyNo(polyNo);
 				doCtpQuote(q);
 				//ctp 开仓接口
 				TradeUtils.addQuoteReq(q);
 			}
		}
	}
	
	
	public void onRtnQuote(CThostFtdcQuoteField c) {
		TradeUtils.addQuote(TradeConvertUtils.convertQuoteRtn(c));
	}
	
	public void onRtnTrade(CThostFtdcTradeField t) {
		TradeUtils.addTrade(TradeConvertUtils.convertTradeRtn(t));
	}
}
